home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / archiver / unix / unz50p1.zoo / match.c < prev    next >
C/C++ Source or Header  |  1992-07-10  |  19KB  |  564 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   match.c
  4.  
  5.   The match() routine recursively compares a string to a "pattern" (regular
  6.   expression), returning TRUE if a match is found or FALSE if not.  This
  7.   version is specifically for use with unzip.c:  as did the previous match()
  8.   from SEA, it leaves the case (upper, lower, or mixed) of the string alone,
  9.   but converts any uppercase characters in the pattern to lowercase if indi-
  10.   cated by the global var pInfo->lcflag (which is to say, string is assumed
  11.   to have been converted to lowercase already, if such was necessary).
  12.  
  13.   ---------------------------------------------------------------------------*/
  14.  
  15.  
  16. #ifdef ZIPINFO
  17. #  undef ZIPINFO   /* make certain there is only one version of match.o */
  18. #endif /* ZIPINFO */
  19. #include "unzip.h"
  20.  
  21. static int  matche              __((register char *p, register char *t));
  22. static int  matche_after_star   __((register char *p, register char *t));
  23.  
  24. /* #include "filmatch.h": */
  25. #ifndef BOOLEAN
  26. #  define BOOLEAN short int      /* v1.2 made it short */
  27. #endif
  28.  
  29. /* match defines */
  30. #define MATCH_PATTERN  6    /* bad pattern */
  31. #define MATCH_LITERAL  5    /* match failure on literal match */
  32. #define MATCH_RANGE    4    /* match failure on [..] construct */
  33. #define MATCH_ABORT    3    /* premature end of text string */
  34. #define MATCH_END      2    /* premature end of pattern string */
  35. #define MATCH_VALID    1    /* valid match */
  36.  
  37. /* pattern defines */
  38. #define PATTERN_VALID  0    /* valid pattern */
  39. #define PATTERN_ESC   -1    /* literal escape at end of pattern */
  40. #define PATTERN_RANGE -2    /* malformed range in [..] construct */
  41. #define PATTERN_CLOSE -3    /* no end bracket in [..] construct */
  42. #define PATTERN_EMPTY -4    /* [..] contstruct is empty */
  43.  
  44. /*----------------------------------------------------------------------------
  45. *
  46. *  Match the pattern PATTERN against the string TEXT;
  47. *
  48. *       match() returns TRUE if pattern matches, FALSE otherwise.
  49. *       matche() returns MATCH_VALID if pattern matches, or an errorcode
  50. *           as follows otherwise:
  51. *
  52. *            MATCH_PATTERN  - bad pattern
  53. *            MATCH_RANGE    - match failure on [..] construct
  54. *            MATCH_ABORT    - premature end of text string
  55. *            MATCH_END      - premature end of pattern string
  56. *            MATCH_VALID    - valid match
  57. *
  58. *
  59. *  A match means the entire string TEXT is used up in matching.
  60. *
  61. *  In the pattern string:
  62. *       `*' matches any sequence of characters (zero or more)
  63. *       `?' matches any character
  64. *       [SET] matches any character in the specified set,
  65. *       [!SET] or [^SET] matches any character not in the specified set.
  66. *
  67. *  A set is composed of characters or ranges; a range looks like
  68. *  character hyphen character (as in 0-9 or A-Z).  [0-9a-zA-Z_] is the
  69. *  minimal set of characters allowed in the [..] pattern construct.
  70. *  Other characters are allowed (ie. 8 bit characters) if your system
  71. *  will support them.
  72. *
  73. *  To suppress the special syntactic significance of any of `[]*?!^-\',
  74. *  in a [..] construct and match the character exactly, precede it
  75. *  with a `\'.
  76. *
  77. ----------------------------------------------------------------------------*/
  78.  
  79. /*----------------------------------------------------------------------------
  80. *
  81. *  Match the pattern PATTERN against the string TEXT;
  82. *
  83. *  returns MATCH_VALID if pattern matches, or an errorcode as follows
  84. *  otherwise:
  85. *
  86. *            MATCH_PATTERN  - bad pattern
  87. *            MATCH_RANGE    - match failure on [..] construct
  88. *            MATCH_ABORT    - premature end of text string
  89. *            MATCH_END      - premature end of pattern string
  90. *            MATCH_VALID    - valid match
  91. *
  92. *
  93. *  A match means the entire string TEXT is used up in matching.
  94. *
  95. *  In the pattern string:
  96. *       `*' matches any sequence of characters (zero or more)
  97. *       `?' matches any character
  98. *       [SET] matches any character in the specified set,
  99. *       [!SET] or [^SET] matches any character not in the specified set.
  100. *       \ is allowed within a set to escape a character like ']' or '-'
  101. *
  102. *  A set is composed of characters or ranges; a range looks like
  103. *  character hyphen character (as in 0-9 or A-Z).  [0-9a-zA-Z_] is the
  104. *  minimal set of characters allowed in the [..] pattern construct.
  105. *  Other characters are allowed (ie. 8 bit characters) if your system
  106. *  will support them.
  107. *
  108. *  To suppress the special syntactic significance of any of `[]*?!^-\',
  109. *  within a [..] construct and match the character exactly, precede it
  110. *  with a `\'.
  111. *
  112. ----------------------------------------------------------------------------*/
  113.  
  114. static int matche(p, t)
  115. register char *p;
  116. register char *t;
  117. {
  118.     register char range_start, range_end;  /* start and end in range */
  119.  
  120.     BOOLEAN invert;             /* is this [..] or [!..] */
  121.     BOOLEAN member_match;       /* have I matched the [..] construct? */
  122.     BOOLEAN loop;               /* should I terminate? */
  123.  
  124.     for (;  *p;  p++, t++) {
  125.  
  126.         /* if this is the end of the text then this is the end of the match */
  127.         if (!*t)
  128.             return ((*p == '*') && (*++p == '\0'))?  MATCH_VALID : MATCH_ABORT;
  129.  
  130.         /* determine and react to pattern type */
  131.         switch (*p) {
  132.  
  133.             /* single any character match */
  134.             case '?':
  135.                 break;
  136.  
  137.             /* multiple any character match */
  138.             case '*':
  139.                 return matche_after_star (p, t);
  140.  
  141.             /* [..] construct, single member/exclusion character match */
  142.             case '[': {
  143.  
  144.                 /* move to beginning of range */
  145.                 p++;
  146.  
  147.                 /* check if this is a member match or exclusion match */
  148.                 invert = FALSE;
  149.                 if ((*p == '!') || (*p == '^')) {
  150.                     invert = TRUE;
  151.                     p++;
  152.                 }
  153.  
  154.                 /* if closing bracket here or at range start then we have a
  155.                    malformed pattern */
  156.                 if (*p == ']')
  157.                     return MATCH_PATTERN;
  158.  
  159.                 member_match = FALSE;
  160.                 loop = TRUE;
  161.  
  162.                 while (loop) {
  163.  
  164.                     /* if end of construct then loop is done */
  165.                     if (*p == ']') {
  166.                         loop = FALSE;
  167.                         continue;
  168.                     }
  169.  
  170.                     /* matching a '!', '^', '-', '\' or a ']' */
  171.                     if (*p == '\\')
  172.                         range_start = range_end = *++p;
  173.                     else
  174.                         range_start = range_end = *p;
  175.  
  176.                     /* if end of pattern then bad pattern (Missing ']') */
  177.                     if (!*p)
  178.                         return MATCH_PATTERN;
  179.  
  180.                     /* check for range bar */
  181.                     if (*++p == '-') {
  182.  
  183.                         /* get the range end */
  184.                         range_end = *++p;
  185.  
  186.                         /* if end of pattern or construct then bad pattern */
  187.                         if ((range_end == '\0') || (range_end == ']'))
  188.                             return MATCH_PATTERN;
  189.  
  190.                         /* special character range end */
  191.                         if (range_end == '\\') {
  192.                             range_end = *++p;
  193.  
  194.                             /* if end of text then we have a bad pattern */
  195.                             if (!range_end)
  196.                                 return MATCH_PATTERN;
  197.                         }
  198.  
  199.                         /* move just beyond this range */
  200.                         p++;
  201.                     }
  202.  
  203.                     /* if the text character is in range then match found.
  204.                      * make sure the range letters have the proper
  205.                      * relationship to one another before comparison
  206.                      */
  207.                     if (range_start < range_end) {
  208.                         if ((*t >= range_start) && (*t <= range_end)) {
  209.                             member_match = TRUE;
  210.                             loop = FALSE;
  211.                         }
  212.                     } else {
  213.                         if ((*t >= range_end) && (*t <= range_start)) {
  214.